"""
route_demo.py: 主要负责绘制ui,事件处理等。
示例命令行： -l "112.1,19.4" -w 1100 -e 800 -a 192.168.1.119
依赖：
astar.py: A*算法的实现放这里。
grid_reader.py: 读取网格数据在这里。
TODO 重要事项！（1）在跨越-180/+180经度线时的地图拼接处理。（2）跨越半个地球导航时的处理。
"""
import datetime
import os
import sys
import time
from optparse import OptionParser
import numpy as np
import pygame
from pygame import surfarray
from pygments.lexer import default

from navieng.astar import AStar
from navieng.grid_reader import GridReader
from tkinter import simpledialog
import tkinter
from navieng.weather_reader import WeatherReader
from navieng.local_cache import LocalCache

def popup_with_entry():
    root = tkinter.Tk()
    root.withdraw() # 隐藏主窗口
    # 创建输入框
    input_str = simpledialog.askstring("设置绘制区域的代价值", "请输入1~127的正整数作为代价：")
    if input_str:
        print("您输入的代价：" + input_str)
        return int(input_str)
    return None

# 常量定义
CELL_SIZE = 4
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
GRAY = (200, 200, 200)
YELLOW = (255, 255, 0)
PURPLE = (128, 0, 128)
DARK_GRAY = (100, 100, 100)
BUTTON_COLOR = (70, 130, 180)
BUTTON_HOVER_COLOR = (100, 150, 200)
POINT_MODE = False

class Button:
    def __init__(self, x, y, width, height, text, action=None):
        self.rect = pygame.Rect(x, y, width, height)
        self.text = text
        self.action = action
        self.is_hovered = False
        self.font = pygame.font.SysFont(None, 16)
        # font_name = pygame.font.match_font('fangsong')
        # self.font = pygame.font.Font(font_name, 16)

    def draw(self, surface):
        color = BUTTON_HOVER_COLOR if self.is_hovered else BUTTON_COLOR
        pygame.draw.rect(surface, color, self.rect, border_radius=5)
        pygame.draw.rect(surface, BLACK, self.rect, 2, border_radius=5)

        text_surf = self.font.render(self.text, True, WHITE)
        text_rect = text_surf.get_rect(center=self.rect.center)
        surface.blit(text_surf, text_rect)

    def check_hover(self, pos):
        self.is_hovered = self.rect.collidepoint(pos)
        return self.is_hovered

    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1 and self.is_hovered:
            if self.action:
                self.action()
                return True
        return False


class PathFinder(AStar):
    def __init__(self, size_cx, size_cy, grid, start, end):
        AStar.__init__(self, size_cx, size_cy, grid, start, end)

        self.setting_start = False
        self.setting_end = False
        self.mode_text = ""
        self.drawing_cost_area = False
        self.current_set_cost = 1 # AStar中默认每一步的cost都是1，所以这里也做相同设置。
        self.cost_rects = []
        self.pixel_array = np.zeros((size_cx, size_cy, 3), dtype=np.uint8)
        # 创建菜单按钮
        self.buttons = [
            Button(10, 10, 80, 28, "set start", self.set_start_mode),
            Button(100, 10, 80, 28, "set end", self.set_end_mode),
            #Button(270, 10, 120, 40, "绘制障碍", self.set_draw_obstacles),
            #Button(400, 10, 120, 40, "擦除障碍", self.set_erase_obstacles),
            Button(190, 10, 80, 28, "set cost", self.draw_cost_area),
            Button(280, 10, 80, 28, "reset cost", self.reset_cost_area)
        ]
        self.is_draw_base_map = True

    def set_start_mode(self):
        self.setting_start = True
        self.setting_end = False
        # self.drawing_obstacles = False
        # self.erasing_obstacles = False

    def set_end_mode(self):
        self.setting_start = False
        self.setting_end = True
        # self.drawing_obstacles = False
        # self.erasing_obstacles = False

    def draw_cost_area(self):
        if self.setting_start or self.setting_end:
            print("draw_cost_area: 无法在设置起点或者终点时使用此功能。")
            return
        print("draw_cost_area")
        cost: int = popup_with_entry()
        if cost is None or cost <= 0 or cost > 127:
            print("输入了无效的值，请输入[1,127]区间的值。")
            return
        self.drawing_cost_area = True
        self.current_set_cost = cost

    def reset_cost_area(self):
        print("重置所有代价区域，恢复为默认值。")
        if self.drawing_cost_area:
            self.drawing_cost_area = False
        for x in range(self.size_cx):
            for y in range(self.size_cy):
                if self.grid[x][y][0] == 0:  # 障碍物
                    self.grid[x][y][1] = 0
                else:  # 可通行区域
                    self.grid[x][y][1] = 1
        self.cost_rects = []
        self.is_draw_base_map = True

    def append_cost_rect(self, rect):
        self.cost_rects.append(rect)

    def set_cost(self, x, y, w, h):
        pos = self.point_revert_y_coord((x, y))
        pos2 = self.point_revert_y_coord((x + w, y + h))
        global POINT_MODE
        if not POINT_MODE:
            xi1, yi1 = pos[0] // CELL_SIZE, pos[1] // CELL_SIZE  # 计算在哪个格子里。
            print("begin:笛卡尔坐标:", pos, "对应格子的索引:", xi1, yi1)
            xi2, yi2 = pos2[0] // CELL_SIZE, pos2[1] // CELL_SIZE  # 计算在哪个格子里。
            print("end:笛卡尔坐标:", pos2, "对应格子的索引:", xi2, yi2)
        else:
            xi1, yi1 = pos[0], pos[1]
            xi2, yi2 = pos2[0], pos2[1]
        # 经过转换后坐标(x1,y1)在左上, (x2,y2)在右下，所以是(y2 -> y1+1)
        for i in range(xi1, xi2+1):
            for j in range(yi2, yi1+1):
                if self.grid[i][j][0] == 1:
                    self.grid[i][j][1] = self.current_set_cost

    def point_revert_y_coord(self, pos):
        global POINT_MODE
        if not POINT_MODE:
            return pos[0], self.size_cy * CELL_SIZE - pos[1]
        else:
            return pos[0], self.size_cy - pos[1] - 1

    def rect_revert_y_coord(self, x, y):
        global POINT_MODE
        if not POINT_MODE:
            return x * CELL_SIZE, (self.size_cy-y-1) * CELL_SIZE, CELL_SIZE, CELL_SIZE
        else:
            raise Exception("rect_revert_y_coord不应在点模式下使用。")
        #return x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE

    def draw_rect_mode(self, screen):
        # 基础可通行不可通行区域
        for x in range(self.size_cx):
            for y in range(self.size_cy):
                if self.grid[x][y][0] == 0:  # 障碍物
                    #screen.set_at((150, 300), BLACK)
                    pygame.draw.rect(screen, BLACK, self.rect_revert_y_coord(x, y))
                else:  # 可通行区域
                    weight = self.grid[x][y][1]
                    if weight != 1:  # 默认weight等于1，让它继续展示白色块。此外可达块的weight不会等于0。
                        color = (0xff - weight & 0xff, 0xff - weight & 0xff, 0xff - weight & 0xff)
                    else:
                        color = WHITE
                    pygame.draw.rect(screen, color, self.rect_revert_y_coord(x, y))
                # 绘制网格线
                pygame.draw.rect(screen, GRAY, self.rect_revert_y_coord(x, y), 1)

        # 绘制已访问的节点
        for pos in self.visited:
            x, y = pos
            pygame.draw.rect(screen, BLUE, self.rect_revert_y_coord(x, y))

        # 绘制开放集中的节点
        for _, pos in self.open_set:
            x, y = pos
            pygame.draw.rect(screen, GREEN, self.rect_revert_y_coord(x, y))

        # 绘制路径
        for pos in self.path:
            x, y = pos
            pygame.draw.rect(screen, YELLOW, self.rect_revert_y_coord(x, y))

        # 绘制起点和终点
        if self.start:
            x, y = self.start
            pygame.draw.rect(screen, RED, self.rect_revert_y_coord(x, y))
        if self.end:
            x, y = self.end
            pygame.draw.rect(screen, PURPLE, self.rect_revert_y_coord(x, y))
        # 绘制菜单栏背景
        # pygame.draw.rect(screen, DARK_GRAY, (0, 0, WIDTH, 60))

    def draw_point_mode(self, screen):
        # 绘制基本数据：障碍物和代价区域
        # 直接创建numpy数组
        if self.is_draw_base_map:
            self.is_draw_base_map = False
            for x in range(self.size_cx):
                for y in range(self.size_cy):
                    if y >= len(self.grid[x]):  # 这里没有数据，视为障碍物
                        # screen.set_at(self.point_revert_y_coord((x, y)), BLACK)
                        raise Exception("因地图数据错误无法渲染，坐标{0}处数据丢失。".format((x,y)))
                    else:
                        rx, ry = self.point_revert_y_coord((x, y))
                        if self.grid[x][y][0] == 0:  # 障碍物
                            self.pixel_array[rx,ry] = [0, 0, 0]
                            #screen.set_at(self.point_revert_y_coord((x, y)), BLACK)  # 修改指定位置的像素颜色
                        else:  # 可通行区域
                            weight = self.grid[x][y][1]
                            if weight != 1:  # 默认weight等于1，让它继续展示白色块。此外可达块的weight不会等于0。
                                #color = (0xff - weight & 0xff, 0xff - weight & 0xff, 0xff - weight & 0xff)
                                self.pixel_array[rx,ry] = [0xff - weight & 0xff, 0xff - weight & 0xff, 0xff - weight & 0xff]
                            else:
                                self.pixel_array[rx,ry] = [255, 255, 255]
                                #color = WHITE
                            #screen.set_at(self.point_revert_y_coord((x, y)), color)
        # 绘制已访问的节点
        for pos in self.visited:
            rx, ry = self.point_revert_y_coord(pos)
            self.pixel_array[rx, ry] = list(BLUE)
            #screen.set_at(self.point_revert_y_coord(pos), BLUE)
        # 绘制开放集中的节点
        for _, pos in self.open_set:
            rx, ry = self.point_revert_y_coord(pos)
            self.pixel_array[rx, ry] = list(GREEN)
            #screen.set_at(self.point_revert_y_coord(pos), GREEN)
        # 绘制路径
        for pos in self.path:
            rx, ry = self.point_revert_y_coord(pos)
            self.pixel_array[rx, ry] = list(YELLOW)
            #screen.set_at(self.point_revert_y_coord(pos), YELLOW)
        # 绘制起点和终点
        if self.start:
            rx, ry = self.point_revert_y_coord(self.start)
            self.pixel_array[rx, ry] = list(RED)
            #screen.set_at(self.point_revert_y_coord(self.start), RED)
        if self.end:
            rx, ry = self.point_revert_y_coord(self.end)
            self.pixel_array[rx, ry] = list(PURPLE)
            #screen.set_at(self.point_revert_y_coord(self.end), PURPLE)
        surfarray.blit_array(screen, self.pixel_array)

    def draw(self, screen):
        screen.fill(WHITE)
        if not POINT_MODE:
            self.draw_rect_mode(screen)
        else:
            self.draw_point_mode(screen)
        # 绘制按钮
        mouse_pos = pygame.mouse.get_pos()
        for button in self.buttons:
            button.check_hover(mouse_pos)
            button.draw(screen)

        # 显示当前模式
        if self.setting_start:
            self.mode_text = "当前模式: 设置起点 (点击网格设置)"
        elif self.setting_end:
            self.mode_text = "当前模式: 设置终点 (点击网格设置)"
        # elif self.drawing_obstacles:
        #     self.mode_text = "当前模式: 绘制障碍 (点击或拖动绘制)"
        # elif self.erasing_obstacles:
        #     self.mode_text = "当前模式: 擦除障碍 (点击或拖动擦除)"
        else:
            self.mode_text = "当前模式: 选择模式"

        # 绘制所有已保存的矩形
        for r in self.cost_rects:
            pygame.draw.rect(screen, (255, 128, 0), r, 2)

    def handle_click(self, x, y):
        if 0 <= x < self.size_cx and 0 <= y < self.size_cy:
            if self.setting_start and self.grid[x][y][0] == 1:
                self.start = (x, y)
                self.setting_start = False
                self.reset_grid()
                return 0
            elif self.setting_end and self.grid[x][y][0] == 1:
                self.end = (x, y)
                self.setting_end = False
                self.reset_grid()
                return 1
        return None


def main(lon: float, lat: float, h_cc: int, v_cc: int, hbase_host, hbase_port, read_threads, weather_config):
    # 初始化pygame
    pygame.init()
    # 创建屏幕
    global POINT_MODE
    if POINT_MODE:
        scx, scy = h_cc, v_cc
    else:
        scx, scy = h_cc * CELL_SIZE, v_cc * CELL_SIZE
    screen = pygame.display.set_mode((scx, scy))
    pygame.display.set_caption("正在从hbase读取地图……")

    test_spark_data = False
    if test_spark_data:
        print("测试从spark保存的数据中读取并展示网格数据，用来验证spark的结果")
        # 定义文件路径
        file_path = r'D:\github\spark-scala-tutorial\HBaseNewAPIReader\target\output.bin'  # 替换为你的文件路径
        # 从文件读取10000字节的二进制数据
        with open(file_path, 'rb') as file:
            data = file.read(10000)  # 读取10000字节
        # 检查数据长度
        if len(data) != 10000:
            raise ValueError("文件中的数据不足10000字节！")
        # 将二进制数据转换为100×100的二维数组（每个元素是一个字节的整数值）
        grid = [[[0,0] for _ in range(100)] for _ in range(100)]
        for i in range(100):
            for j in range(100):
                grid[i][j] = [data[i * 100 + j], 0]
    else:
        # -----------------读取数据开始-------------------
        # 从hbase中读取数据: 总共GRID_SIZE乘以GRID_SIZE个格子
        # cache = LocalCache(r"D:\source\python\navigation-plan-engine\postgres2osm\test\config\navieng.json")
        # if cache.map_cache_ready:
        #     grid = cache.read_map_cache(lon, lat, h_cc, v_cc)  # 考虑参数问题。
        # else:
        # NOTE: TEMPORARY DISABLED FOR A* DEMO
        print(datetime.datetime.now(), f"开始从hbase({hbase_host}:{hbase_port})读取地图……")
        start_time = time.perf_counter()
        reader = GridReader(hbase_host, hbase_port, read_threads)
        grid = reader.read_grid_data(lon, lat, h_cc, v_cc)  # 是否可通行grid[i][j][0], 通行代价grid[i][j][1]
        print(datetime.datetime.now(), "地图数据读取完毕！耗时：", time.perf_counter() - start_time, "秒")

        # NOTE: TEMPORARY DISABLED FOR A* DEMO
        # if cache.weather_cache_ready:
        #     grid_wea = cache.read_weather_cache(lon, lat, h_cc, v_cc)  # 考虑参数问题。
        # else:
        #     weather = WeatherReader(weather_config, hbase_host, hbase_port)
        #     weather.dump_config()  # 测试，打印关键的配置信息。
        #     grid_wea = weather.read_weather(lon, lat, h_cc, v_cc)
        # grid i行j列 => weather的((lon * 100)+i)//25, ((lat * 100)+j)//25

    for i in range(0, h_cc):
        for j in range(0, v_cc):
            index_of_weather_cost_x = round((((lon+180.0) * 100) + i) // 25)
            index_of_weather_cost_y = round((((lat+90.0) * 100) + j) // 25)
            # print("寻路网格中的坐标是:", i, j, ",天气代价网格中的坐标是：", index_of_weather_cost_x, index_of_weather_cost_y)
            if grid[i][j][0] == 1:
                # NOTE: THE WEATHER SDK HAS CHANGED, TEMPORARY DISABLE THE WEATHER CODE.
                # 目前只有天气权重，所以我们直接用天气权重的就好。
                # tmp1 = grid_wea[index_of_weather_cost_x][index_of_weather_cost_y]
                # if tmp1 != 255:
                #     grid[i][j][1] = tmp1 // 10  # 通行代价的数值不能太大，否则目前的预测算法会出问题。这里要慢慢调整。
                # else:
                #     grid[i][j][1] = tmp1
                # print("代价值是：", grid[i][j][1])
                grid[i][j][1] = 1
    # -----------------读取数据结束-------------------
    pygame.display.set_caption("寻路算法演示 - A*算法:")
    path_finder = PathFinder(h_cc, v_cc, grid, (0,0), (h_cc-1, v_cc-1))
    pygame.display.set_caption("寻路算法演示 - A*算法:" + path_finder.mode_text)
    cur_mode_text = path_finder.mode_text
    # 主循环
    running = True
    clock = pygame.time.Clock()
    auto_step = False
    step_delay = 0.01  # 秒
    pygame.key.stop_text_input()  # 停止文本输入模式

    rect_drawing = False
    rect_start_pos = None
    rect_current_pos = None

    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            # 处理按钮事件
            skip_click = False
            for button in path_finder.buttons:
                if button.handle_event(event):
                    skip_click = True

            # caption
            if cur_mode_text != path_finder.mode_text:
                cur_mode_text = path_finder.mode_text
                pygame.display.set_caption("寻路算法演示 - A*算法:" + path_finder.mode_text)

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    path_finder.step()
                elif event.key == pygame.K_r:
                    path_finder.reset_grid()
                    path_finder.is_draw_base_map = True
                    # path_finder.reset_cost_area()
                elif event.key == pygame.K_a:
                    auto_step = not auto_step
                    path_finder.running = auto_step
                elif event.key == pygame.K_s:
                    path_finder.running = True
                elif event.key == pygame.K_x:
                    path_finder.finished = False
                    path_finder.running = True
                    start_time = time.perf_counter()
                    while not path_finder.finished:
                        path_finder.step()
                    end_time = time.perf_counter()
                    print("寻路完成，耗时:{0}秒".format(end_time-start_time))

            if not skip_click:
                if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                    print("点击游戏窗口坐标:", event)
                    # 我们的y轴是从正常的笛卡尔坐标系Y轴，和game窗口的y方向是反的，需要做一下调整。
                    pos = path_finder.point_revert_y_coord(event.pos)
                    if not POINT_MODE:
                        xi, yi = pos[0] // CELL_SIZE, pos[1] // CELL_SIZE  # 计算在哪个格子里。
                    else:
                        xi, yi = pos[0], pos[1]
                    print("笛卡尔坐标:", pos, "对应格子的索引:", xi, yi)
                    if path_finder.drawing_cost_area:
                        rect_drawing = True
                        rect_start_pos = event.pos
                        rect_current_pos = event.pos
                        print("rect_start_pos:", pos, rect_current_pos)
                    else:
                        r = path_finder.handle_click(xi, yi)
                        if r == 0:
                            show_message(screen, "start point has set to ({0},{1})".format(xi, yi))
                        elif r ==1:
                            show_message(screen, "end point has set to ({0},{1})".format(xi, yi))
                elif event.type == pygame.MOUSEMOTION:
                    if path_finder.drawing_cost_area:
                        if rect_drawing:
                            rect_current_pos = event.pos
                elif event.type == pygame.MOUSEBUTTONUP:
                    if event.button == 1 and rect_drawing:  # 左键释放
                        rect_drawing = False
                        rect_end_pos = event.pos
                        # 将矩形添加到列表中 (起始点, 宽高)
                        x = min(rect_start_pos[0], rect_end_pos[0])
                        y = min(rect_start_pos[1], rect_end_pos[1])
                        w = abs(rect_end_pos[0] - rect_start_pos[0])
                        h = abs(rect_end_pos[1] - rect_start_pos[1])
                        if w > 0 and h > 0:  # 避免零大小的矩形
                            path_finder.append_cost_rect((x, y, w, h))
                            path_finder.set_cost(x, y, w, h)
                            path_finder.drawing_cost_area = False
                            path_finder.is_draw_base_map = True

        if auto_step and not path_finder.finished:
            path_finder.step()
            time.sleep(step_delay)

        path_finder.draw(screen)

        # 绘制当前正在拖动的矩形
        if rect_drawing and rect_start_pos and rect_current_pos:
            x = min(rect_start_pos[0], rect_current_pos[0])
            y = min(rect_start_pos[1], rect_current_pos[1])
            w = abs(rect_current_pos[0] - rect_start_pos[0])
            h = abs(rect_current_pos[1] - rect_start_pos[1])
            if w > 0 and h > 0:
                pygame.draw.rect(screen, RED, (x, y, w, h), 2)

        pygame.display.flip()
        clock.tick(30)

    pygame.quit()

def show_message(screen, message):
    text_font = pygame.font.SysFont(None, 16)
    #font_name = pygame.font.match_font('fangsong') # ubuntu上没有这个字体。
    #text_font = pygame.font.Font(font_name, 16)
    text_surface = text_font.render(message, True, (255, 255, 255))
    text_rect = text_surface.get_rect()
    text_rect.center = (screen.get_width() // 2, screen.get_height() // 2)
    pygame.draw.rect(screen, (0, 0, 0), (text_rect.left - 10, text_rect.top - 10, text_rect.width + 20, text_rect.height + 20))
    screen.blit(text_surface, text_rect)
    pygame.display.update()
    pygame.time.delay(1000)

def print_error_and_help(parser, error_msg):
    print(error_msg, file=sys.stderr)
    parser.print_help(sys.stderr)

def main_startup():
    """
    这个函数用来检查命令行参数是否正确。确认参数正确无误后调用main函数。
    """
    parser = OptionParser()
    parser.add_option("-l", "--lonlat", action="store", type="string", dest="lon_lat",
                      help="输入地图的起始点（左下角），用逗号分割经纬度，经度在前纬度在后，经纬度之间不能有空格，例如118.1,24.4,"
                           "此为必要参数。")
    parser.add_option("-e", "--height", action="store", type="string", dest="grid_height",
                      help="垂直方向的格子数，格子高是0.01纬度。例如100表示区域的纬度是(起始点，起始点+1度）,此为必要参数。")
    parser.add_option("-w", "--width", action="store", type="string", dest="grid_width",
                      help="水平方向的格子数，格子宽是0.01经度。例如90表示区域的经度是（起始点，起始点+0.9度）,此为必要参数。")
    parser.add_option("-a", "--hbase_host", action="store", type="string", dest="hbase_host",
                      default="192.168.1.208", help="指定hbase服务器的host,如不指定默认值是192.168.1.208")
    parser.add_option("-p", "--hbase_port", action="store", type="int", dest="hbase_port", default=10000,
                      help="指定hbase服务器的port,如不指定则默认为10000端口")
    parser.add_option("-m", "--max-threads", action="store", type="int", dest="max_threads", default=8,
                      help="指定工作线程数量，如不指定则默认8个线程。")
    parser.add_option("-c", "--weather-config", action="store", dest="weather_config",
                      help="从hbase中读取、解析天气数据时用到的配置文件")

    # 翻转坐标方向的选项保留未用，未来有需要再加
    # parser.add_option("-r", "--revert_horizontal", action="store_true", dest="revert_horizontal", default=False,
    #                   help="翻转水平方向。假设输入了width=100，正常情况下（起始点，起始点+1度）,翻转后变成（起始点，起始点-1度）")
    # parser.add_option("-v", "--rever_vertical", action="store_true", dest="vert_vertical", default=False,
    #                   help="翻转垂直方向。假设输入了height=100，正常情况下（起始点，起始点+1度）,翻转后变成（起始点，起始点-1度）")
    opts, _ = parser.parse_args()

    if opts.lon_lat is None:
        print_error_and_help(parser, "必须提供地图的起始点经纬度。")
        return -1
    else:
        temp = str(opts.lon_lat).replace(' ', '')
        l = temp.split(',')
        lon,lat = l[0], l[1]
        if (lon is None or lat is None or lon == '' or lat == ''
                or float(lon) < -180.0 or float(lon) > 180.0
                or float(lat) < -90.0 or float(lat) > 90.0):
            print_error_and_help(parser, "经纬度的格式错误")
            return -1

    if opts.grid_width:
        h_cc = int(opts.grid_width)
        if h_cc <= 0:
            print_error_and_help(parser, "x方向的格子数必须是一个正整数，请指定。")
            return -1
    else:
        print("必须提供x方向的格子数，请使用‘-w’, ‘--width’指定。")
        return -1

    if opts.grid_height:
        v_cc = int(opts.grid_height)
        if v_cc <= 0:
            print_error_and_help(parser, "y方向的格子数必须是一个正整数，请指定。")
            return -1
    else:
        print_error_and_help(parser, "必须提供y方向的格子数，请使用'-e', '--height'指定。")
        return -1

    weather_config = opts.weather_config
    if not opts.weather_config:
        weather_config = os.path.normpath(os.path.join(os.path.dirname(sys.argv[0]), "config/weather.json"))

    # 根据分辨率动态调整格子大小
    # 如果 < 100
    global CELL_SIZE, POINT_MODE
    if v_cc <= 100 and h_cc <= 100:
        CELL_SIZE = 8
    elif v_cc <= 200 and h_cc <= 200:
        CELL_SIZE = 4
    else:
        POINT_MODE = True

    print("展示区域:", lon, lat, h_cc, v_cc)


    main(float(lon), float(lat), h_cc, v_cc, opts.hbase_host, opts.hbase_port, opts.max_threads, weather_config)

if __name__ == "__main__":
    #cProfile.run("main_startup()", sort="cumtime")  # 运行性能分析工具
    main_startup()